一道比较难想的DP
可以想到,每个面额的钞票之间是可以独立计算的
那么就可以对于每一种面额的钞票单独考虑,接下来就是状态的定义了
有一种比较好想的状态就是定义 fi,x,y,z 表示前 i 种钞票, 每个人分别有多少钱,但很明显会超空间.
仔细观察可以发现,钞票的总面额是不变的,那么状态就可以优化掉一维,只需要表示出两个人所有的面额就可以计算出第三个人
然后状态的转移就比较简单了,直接枚举钞票的数量就行了
代码
#include<iostream> #include<cstring> #include<cstdio> #define INF 0x3f3f3f3f using namespace std;
int f[7][1005][1005]; int x1, x2, x3, sum; int n[4][7], s[4], cnt[7]; int val[7] = {0, 100, 50, 20, 10, 5, 1};
int main() { scanf("%d%d%d", &x1, &x2, &x3); for (int i = 1; i <= 3; i++) for (int j = 1; j <= 6; j++) { scanf("%d", &n[i][j]); sum += n[i][j] * val[j], s[i] += n[i][j] * val[j]; cnt[j] += n[i][j]; } memset(f, 0x3f, sizeof(f)); f[0][s[1]][s[2]] = 0; for (int i = 1; i <= 6; i++) { for (int j = 0; j <= sum; j++) { for (int k = 0; k + j <= sum; k++) { if (f[i - 1][j][k] == INF) continue; f[i][j][k] = f[i - 1][j][k]; for (int t1 = 0; t1 <= cnt[i]; t1++) { for (int t2 = 0; t2 + t1 <= cnt[i]; t2++) { int now1 = j - (n[1][i] - t1) * val[i]; int now2 = k - (n[2][i] - t2) * val[i]; int t3 = cnt[i] - t1 - t2; if (now1 >= 0 && now2 >= 0 && sum >= now1 + now2) { int t = abs(n[1][i] - t1) + abs(n[2][i] - t2) + abs(n[3][i] - t3); f[i][now1][now2] = min(f[i][now1][now2], f[i - 1][j][k] + t / 2);//除以2是因为是交换 } } } } } } int ans = INF, s1 = s[1] - x1 + x3, s2 = s[2] - x2 + x1; for (int i = 0; i <= 6; i++) ans = min(ans, f[i][s1][s2]); if (s1 < 0 || s2 < 0 || sum < s1 + s2 || ans == INF) printf("impossible"); else printf("%d", ans); return 0; }
|